package com.kexl.activiti.demo.controller;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @classname: IndexController
 * @description:
 * @author: kexl
 * @create: 2021-03-12 14:12
 * @version: 1.0
 **/
@Controller
@Slf4j
public class IndexController {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private HistoryService historyService;
    @Autowired
    private RuntimeService runtimeService;

    /**
     *
     * @return
     */
    @RequestMapping("test")
    @ResponseBody
    public String test(){
        return "ok";
    }

    /**
     *
     * @param modelAndView
     * @return
     */
    @RequestMapping("index")
    public ModelAndView index(ModelAndView modelAndView) {
        modelAndView.setViewName("index");
        List<Model> list=repositoryService.createModelQuery().list();
        log.info("已发布流程：{}",list.size());
        /*List<ProcessDefinition> processDefinitionList=repositoryService.createProcessDefinitionQuery().active().latestVersion().list();
        log.info("> 处于激活状态的最新版本的流程定义数量: " + processDefinitionList.size());*/

        modelAndView.addObject("modelList", list);

        return modelAndView;
    }

    /**
     * 发布流程
     * @param modelId 模型ID
     * @return
     */
    @ResponseBody
    @RequestMapping("publish")
    public Object publish(String modelId){
        log.info("流程部署入参modelId：{}",modelId);
        Map<String, String> map = new HashMap<String, String>();
        try {
            Model modelData = repositoryService.getModel(modelId);
            byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
            if (bytes == null) {
                log.info("部署ID:{}的模型数据为空，请先设计流程并成功保存，再进行发布",modelId);
                map.put("code", "FAILURE");
                return map;
            }
            JsonNode modelNode = new ObjectMapper().readTree(bytes);
            BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
            Deployment deployment = repositoryService.createDeployment()
                    .name(modelData.getName())
                    .addBpmnModel(modelData.getKey()+".bpmn20.xml", model)
                    .deploy();
            modelData.setDeploymentId(deployment.getId());
            repositoryService.saveModel(modelData);
            map.put("code", "SUCCESS");
        } catch (Exception e) {
            log.info("部署modelId:{}模型服务异常：{}",modelId,e);
            map.put("code", "FAILURE");
        }
        log.info("流程部署出参map：{}",map);
        return map;
    }

    /**
     * 撤销流程定义
     * @param modelId 模型ID
     * @return
     */
    @ResponseBody
    @RequestMapping("revokePublish")
    public Object revokePublish(String modelId){
        log.info("撤销发布流程入参modelId：{}",modelId);
        Map<String, String> map = new HashMap<String, String>();
        Model modelData = repositoryService.getModel(modelId);
        if(null != modelData){
            try {
                /**
                 * 参数不加true:为普通删除，如果当前规则下有正在执行的流程，则抛异常 
                 * 参数加true:为级联删除,会删除和当前规则相关的所有信息，包括历史 
                 */
                repositoryService.deleteDeployment(modelData.getDeploymentId(),true);
                map.put("code", "SUCCESS");
            } catch (Exception e) {
                log.error("撤销已部署流程服务异常：{}",e);
                map.put("code", "FAILURE");
            }
        }
        log.info("撤销发布流程出参map：{}",map);
        return map;
    }

    /**
     * 删除流程实例
     * @param modelId 模型ID
     * @return
     */
    @ResponseBody
    @RequestMapping("delete")
    public Object deleteProcessInstance(String modelId){
        log.info("删除流程实例入参modelId：{}",modelId);
        Map<String, String> map = new HashMap<String, String>();
        Model modelData = repositoryService.getModel(modelId);
        if(null != modelData){
            try {
                ProcessInstance pi = runtimeService.createProcessInstanceQuery().processDefinitionKey(modelData.getKey()).singleResult();
                if(null != pi) {
                    runtimeService.deleteProcessInstance(pi.getId(), "");
                    historyService.deleteHistoricProcessInstance(pi.getId());
                }
                map.put("code", "SUCCESS");
            } catch (Exception e) {
                log.error("删除流程实例服务异常：{}",e);
                map.put("code", "FAILURE");
            }
        }
        log.info("删除流程实例出参map：{}",map);
        return map;
    }
}

